/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - graphics/scene
// Copyright( c) 2015.  All Rights Reserved
//
// File:		AEStaticGeometryInstance.h
// Author:		Gianluca Belardelli
// Date:		19/06/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESTATICGEOMETRYINSTANCE_H_
#define _AESTATICGEOMETRYINSTANCE_H_

/// \brief
///   Enumeration for static geometry types. Each static geometry instance can be of one of these
///   types.
enum AEStaticGeometryType
{
	AESTATICGEOMTYPE_MESHINSTANCE = 1,      ///< Geometry is a VisStaticSubmeshInstance_cl
	AESTATICGEOMTYPE_TERRAIN = 2,           ///< Geometry is a Vision terrain sector
	AESTATICGEOMTYPE_FIRSTCUSTOM = 3        ///< Geometry has a custom type
};

/// \brief
///   Class for static geometry instances, including Vision's static submesh instances, terrain,
///   and custom geometry instances
/// 
/// Abstract base class for static geometry instances, including Vision's static submesh instances,
/// terrain, and custom geometry instances
/// 
/// All static geometry classes should be derived from this class. For instance, Vision's static
/// submesh instances and terrain sectors are subclasses of AEStaticGeometryInstance.
/// 
/// Unlike scene elements derived from VisObject3D_cl, subclasses of AEStaticGeometryInstance
/// should not alter their position or orientation dynamically. They do not perform visibility zone
/// tracking.
/// 
/// Static Geometry Instances are kept in a global element manager.
/// 
/// Custom static geometry instance types have to use geometry types starting with
/// STATIC_GEOMETRY_TYPE_FIRSTCUSTOM.
class AEStaticGeometryInstance : public AEVisibilityData
{
	//friend class VisVisibilityZone_cl;
	//friend class VisStateHandler_cl;
	//friend class VisionVisibilityCollector_cl;

// Members
protected:
	AEStaticGeometryType m_eGeometryType;
	
	AEMaterial *m_lpMaterial;
	AEUINT16 m_uiLightMask;
	AEUINT16 m_uiTraceMask;
	
	//AEUINT32 m_iTagged;
	AEUINT32 m_uiSortingKey;
	
	//VisVisibilityObjectPtr m_spVisObject; ///< visibility object
	//VisVisibilityZone_cl *m_pVisibilityZone;
	//DynArray_cl<VisVisibilityZone_cl *>m_pAdditionalVisZones;
	
	// Lightmap/LightMask information
	AEVector4f m_vcLightmapScaleOffs;
	AETexturePtr m_spLightmapTexture[4]; ///< diffuse and 3 dot3 lightmaps
	AEBOOL32 m_bCastDynamicShadows;
	AEBOOL32 m_bCastStaticShadows;
	AEINT16 m_sVisibilityZoneAssignmentCount;
	AEINT16 m_sNumLightMaskEntries;
	//VisLightMask_cl *m_pLightMaskEntries;
	AEINT64 m_n64CustomID;

// Methods
protected:
	AE_DLLIMPEXP void setPassType( AEMaterial &mtlMaterial );

public:
	/** @name Construction and Destruction */
	/// @{
	/// \brief
	///   Constructor of the static geometry instance base class.
	AE_DLLIMPEXP AEStaticGeometryInstance( void );
	
	/// \brief Destructor of the static geometry instance base class.
	AE_DLLIMPEXP virtual ~AEStaticGeometryInstance( void );
	
	/// @}
	/** @name Virtual Functions */
	/// @{
	/// \brief
	///   Virtual render method. Needs to be implemented in subclasses.
	/// 
	/// The Vision engine will call this method for each object inside a
	/// VisStaticGeometryInstanceCollection_cl passed to one of the appropriate rendering methods in
	/// the VisRenderLoopHelper_cl class.
	/// 
	/// The order in which the instances' render methods are called depends on their sorting key,
	/// which can be set using the m_uiSortingKey member. See the documentation of ComputeSortingKey
	/// for more details.
	/// 
	/// The collection and index parameters can be used inside the Render function to reduce state
	/// setup overhead by checking which instance types are being rendered before and after the
	/// current geometry instance.
	/// 
	/// Typically, rendering should be performed using the BeginMeshRendering/EndMeshRendering
	/// functionality provided by the VisRenderLoopHelper_cl class.
	/// 
	/// \param pShader
	///   Shader with which to render the geometry.
	/// 
	/// \param allInstances
	///   Reference to the collection of static geometry instances being rendered in this draw call.
	/// 
	/// \param iThisIndex
	///   Index of this static geometry instance within the passed collection.
	/// 
	/// \param ePassType
	///   Passtype (one of the VPassType_e enumeration members).
	//AE_DLLIMPEXP virtual void Render( VCompiledShaderPass *pShader, const VisStaticGeometryInstanceCollection_cl &allInstances, AEINT32 iThisIndex, VPassType_e ePassType) {}
	AE_DLLIMPEXP virtual void Render( void ) = 0;
	/// \brief
	///   Virtual function computing the sorting key for this static geometry instance.
	/// 
	/// Sorting keys can be used to influence the order in which geometry is drawn. Since sorting
	/// keys of static geometry instances should not be changed every frame, this functionality is
	/// mostly present  to ensure low state change overhead by grouping similar instances together.
	/// For example, instances with the same texture, lightmap, or tranformation matrix may have
	/// identical sorting keys in order to ensure they are drawn right after each other.
	///
	/// The sorting key computation of the abstract AEStaticGeometryInstance base class stores
	/// the following data in the sorting key:
	/// \li Bit  31: 1 = Opaque, 0 = any transparency type
	/// \li Bits 29, 30: Geometry type (static mesh, terrain, custom geometry)
	/// \li Bits 25 to 28: Surface sorting key (lower four bits)
	/// \li Bits 17 to 24: Source Effect of the applied shader technique
	/// \li Bits 9 to 16: Surface Pointer
	/// Derived classes should first call this method in their own ComputeSortingKey() implementations.
	/// The lower ten bits can be set in derived classes if desired. Derived classes should NEVER
	/// overwrite the upper seven bits (geometry type, surface sorting key), though they may overwrite
	/// Source Effect and Surface Pointer if desired.
	/// 
	/// Do not use this functionality to perform frame-by-frame sorting (e.g. front to back).
	AE_DLLIMPEXP virtual void ComputeSortingKey( void );
	
	/// \brief
	///   Overridable for profiling purposes (used for displaying in
	///   DEBUGRENDERFLAG_OBJECT_TRIANGLECOUNT mode). Specifies the number of primitives to be
	///   rendered
	AE_DLLIMPEXP virtual AEINT32 GetNumPrimitives( void );
	
	/// \brief
	///   Overridable for accessing the supported vertex stream mask. This function is not used for rendering
	AE_DLLIMPEXP virtual AEINT32 GetSupportedStreamMask( void );
	
	///
	/// @}
	///
	
	///
	/// @name Setters and Getters For Common Properties
	/// @{
	///
	
	/// \brief
	///   Empty overridable to render the collision mesh in line mode
	AE_DLLIMPEXP virtual void DebugRenderCollisionMesh( AEColor crMeshColor, AEColor crNormalColor, AEFLOAT32 fNormalLength );
	
	
	
	/// \brief
	///   Assigns a visibility object to this geometry instance.
	///
	///The assigned object will additionally filter out geometry instances in the visibility collector. See implementation in
	///VisionVisibilityCollector_cl::PostProcessVisibilityResults().
	///There can only be one visibility object assigned. By default no visibility object is assigned so that frustum/portal culling
	///is applied. Visibility objects can be assigned visually inside vForge.
	///
	/// \param pVisObj
	///   Visibility object to assign. Can be NULL to remove the reference
	/*void SetVisibilityObject( VisVisibilityObject_cl *pVisObj )
	{ 
	m_spVisObject = pVisObj;
	}*/
	
	
	/// \brief
	///   Returns the visibility object that has been set via SetVisibilityObject
	/*VisVisibilityObject_cl *GetVisibilityObject() const
	{ 
	return m_spVisObject;
	}*/
	
	/// \brief
	///   Sets the light influence bitmask for this geometry instance. This can be used for
	///   fine-grained control regarding which scene elements are affected by which light source.
	AE_FORCEINLINE void SetLightInfluenceBitmask( AEUINT16 uiLightMask ) { m_uiLightMask=uiLightMask; }
	
	/// \brief
	///   Returns the previously set light influence bitmask for this geometry instance.
	AE_FORCEINLINE AEUINT16 GetLightInfluenceBitmask( void ) const { return m_uiLightMask; }
	
	/// \brief
	///   Specifies whether this geometry instance casts dynamic (stencil) shadows.
	AE_FORCEINLINE void SetCastDynamicShadows( AEBOOL32 bStatus ) { m_bCastDynamicShadows=bStatus; }
	
	/// \brief
	///   Returns whether this static geometry instance casts dynamic (stencil) shadows.
	AE_FORCEINLINE AEBOOL32 GetCastDynamicShadows( void ) const { return m_bCastDynamicShadows; }
	
	/// \brief
	///   Returns the sorting key of this static geometry instance previously computed by
	///   ComputeSortingKey.
	AE_FORCEINLINE AEINT32 GetSortingKey( void ) const { return m_uiSortingKey; }
	
	/// \brief
	///   Returns this static geometry instance's geometry type.
	/// 
	/// For legal values, see the AEStaticGeometryType enumeration.
	/// 
	/// The m_eGeometryType member should be set inside the constructor/initializer of custom
	/// subclasses of the AEStaticGeometryInstance class.
	/// 
	/// \return
	///   AEStaticGeometryType: Geometry type of this static mesh instance.
	AE_FORCEINLINE AEStaticGeometryType GetGeometryType( void ) const { return m_eGeometryType; }
	
	/// \brief
	///   Sets the surface (material) of this static geometry instance. If the material is
	///   translucent, the translucent flag is set as well.
	AE_DLLIMPEXP void SetMaterial( AEMaterial *lpMaterial );
	
	/// \brief
	///   Returns the surface (material) of this static geometry instance.
	AE_FORCEINLINE AEMaterial *GetMaterial( void ) const { return m_lpMaterial; }
	
	/// \brief
	///   Assign a custom uder ID to this instance. This value is ignored by the engine but it is serialized to VArchive in SerializeX
	AE_FORCEINLINE void SetCustomID( AEINT64 n64ID ) { m_n64CustomID = n64ID ;}
	
	/// \brief
	///   Returns the value that has been set with SetCustomID. The default value is 0
	AE_FORCEINLINE AEINT64 GetCustomID( void ) const {return m_n64CustomID;}
	
	///
	/// @}
	///
	
	///
	/// @name Visibility-related Functionality
	/// @{
	///
	
	/// \brief
	///   Removes this static mesh instance from all visibility zones. Note that this operation can
	///   consume some time.
	AE_DLLIMPEXP void RemoveFromAllVisibilityZones( void );
	
	///
	/// @}
	///
	
	///
	/// @name Streaming Zones
	/// @{
	///
	
	/// \brief
	///   Overridable to return the owner zone. This default implementation returns NULL. However,
	///   the VisStaticSubmeshInstance_cl::GetParentZone override returns the parent zone of the
	///   static mesh instance
	/*AE_DLLIMPEXP virtual IVisZone_cl *GetParentZone() 
	{
	return NULL;
	}*/
	
	///
	/// @}
	///
	
	///
	/// @name Tagging
	/// @{
	///
	
	/// \brief
	///   Tags this static mesh instance.
	/*AE_FORCEINLINE void Tag() { m_iTagged = m_iTagCtr; }
	
	/// \brief
	///   Returns true if this mesh instance is currently tagged.
	AE_FORCEINLINE AEBOOL32 IsTagged() { return (m_iTagged == m_iTagCtr); }
	
	/// \brief
	///   Resets the tagged states for all static geometry instances.
	static AE_FORCEINLINE void ResetTags() { m_iTagCtr++; }
	
	/// \brief
	///   Returns the current global tag index that is used. It is not increased.
	static AE_FORCEINLINE AEUINT32 GetCurrentGlobalTag() {return m_iTagCtr;}
	*/
	///
	/// @}
	///
	
	///
	/// @name Lightmapping/Lightmask-related Functionality
	/// @{
	///
	
	/// \brief
	///   Internal function called by vForge.
	/*AE_DLLIMPEXP virtual AEBOOL32 ApplyLightmapInfo(VLightmapSceneInfo &sceneInfo, VLightmapPrimitive *pPrim, AEINT32 iMaterialIndex);
	
	/// \brief
	///   Internal function called by vForge.
	AE_DLLIMPEXP virtual void ResetStaticLighting();
	*/
	/// \brief
	///   Sets the lightmap texture for this geometry index. The iSubIndex parameter is used to
	///   specify the index of the lightmap for dot3 lightmapping (0=regular lightmap, 1/2/3=texture
	///   channels for dot3 lightmapping).
	AE_FORCEINLINE void SetLightmapTexture( AETexture *lpTex, AEINT32 nSubIndex ) { AEASSERT(nSubIndex>=0 && nSubIndex<4); m_spLightmapTexture[nSubIndex]=lpTex; }
	
	/// \brief
	///   Returns the lightmap texture previously set with SetLightmapTexture.
	AE_FORCEINLINE AETexture *GetLightmapTexture( AEINT32 nSubIndex ) const { AEASSERT(nSubIndex>=0 && nSubIndex<4); return m_spLightmapTexture[nSubIndex]; }
	
	/// \brief
	///   Sets the scaling and offset for this static geometry instance on the lightmap texture.
	AE_FORCEINLINE void SetLightmapScaleOffset( const AEVector4f &vcScaleOffs ) { m_vcLightmapScaleOffs = vcScaleOffs; }
	
	/// \brief
	///   Returns the lightmap scaling and offset parameters previously set with
	///   SetLightmapScaleOffset.
	AE_FORCEINLINE const AEVector4f &GetLightmapScaleOffset( void ) const { return m_vcLightmapScaleOffs; }
	
	/// \brief
	///   Returns the number of lightmask entries for this instance, i.e. the number of modifiable
	///   light sources that affect this instance
	AE_FORCEINLINE AEINT32 GetNumLightMaskEntries( void ) const { return m_sNumLightMaskEntries; }
	
	/// \brief
	///   Returns the lightmask entry with specified index (must be in range
	///   [0..GetNumLightMaskEntries()-1])
	/*AE_FORCEINLINE VisLightMask_cl &GetLightMaskEntry(AEINT32 iIndex) const 
	{ 
	AEASSERT(iIndex>=0 && iIndex<m_sNumLightMaskEntries);
	return m_pLightMaskEntries[iIndex];
	}*/
	
	/// \brief
	///   Returns the lightmask entry that represents the light source. The return value can be NULL
	/*AE_FORCEINLINE VisLightMask_cl *GetLightMaskEntry(const VisLightSource_cl *pLight) const
	{
	VisLightMask_cl *pSM = m_pLightMaskEntries;
	for (AEINT32 i=0;i<m_sNumLightMaskEntries;i++,pSM++)
	{
	  if (pSM->m_pLight==pLight)
	    return pSM;
	}
	return NULL;
	}*/
	
	
	///
	/// @}
	///
	
	///
	/// @name Static Callbacks
	/// @{
	///
	
	/// \brief
	///   Static callback that gets triggered inside the constructor of a AEStaticGeometryInstance instance.
	///   The data object can be casted to VisStaticGeometryInstanceObject_cl which contains the instance pointer.
	//VISION_APIDATA static VisCallback_cl OnStaticGeometryInstanceCreated;
	
	/// \brief
	///   Static callback that gets triggered inside the destructor of a AEStaticGeometryInstance instance.
	///   The data object can be casted to VisStaticGeometryInstanceObject_cl which contains the instance pointer.
	//VISION_APIDATA static VisCallback_cl OnStaticGeometryInstanceDestroyed;
	
	///
	/// @}
	///
	
	
	// INTERNAL:
	
	AE_FORCEINLINE static AEUINT32 GetVisDataOffset( void ) { return offsetof(AEStaticGeometryInstance, m_bbBoundingBox); }
	
	AE_FORCEINLINE AEINT32 GetVisibilityZoneAssignmentCount( void ) const {return m_sVisibilityZoneAssignmentCount;}
	//AE_DLLIMPEXP AEBOOL32 IsAssignedToVisibilityZone(VisVisibilityZone_cl *pZone);
	//AE_DLLIMPEXP void AddVisibilityZone(VisVisibilityZone_cl *pZone);
	//AE_DLLIMPEXP void RemoveVisibilityZone(VisVisibilityZone_cl *pZone);
	/*AE_FORCEINLINE VisVisibilityZone_cl *GetVisibilityZone(AEINT32 iIndex) { 
	AEASSERT(iIndex < m_sVisibilityZoneAssignmentCount);
	if (iIndex==0)
	  return m_pVisibilityZone;
	else
	  return m_pAdditionalVisZones[iIndex-1];
	}
	*/
	AE_DLLIMPEXP void DebugShowObjectRenderOrder( void );
	
	AE_DLLIMPEXP void DebugShowMaterialShader( void );
	
	
	///
	/// @}
	///

};

#endif // _AESTATICGEOMETRYINSTANCE_H_
